#!/usr/bin/perl
# Subversion: $Id: skelton.pl 3 2009-05-09 20:13:17Z andrewault $
# $HeadURL: http://daemon-kit.googlecode.com/svn/trunk/init.d/skeleton.pl $
#
# Program: skeleton.pl
# Part of: daemon-kit at http://code.google.com/p/daemon-kit/
# Author: Andrew Ault
# Created: 2009-05-08
# Note: For best results, set editor tab width to 4.
#
# This file is part of Daemon-kit.
#
# Daemon-kit is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Daemon-kit is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Daemon-kit.  If not, see <http://www.gnu.org/licenses/>.

use strict;
use warnings;

# For most uses, you probably just need to modify the values in the Customization block.
# Then, rename the program to match the name of the daemon to be controled.
# See the project for detailed instructions on how to fully set up the system.
#
# Customization block
my $command      = "";   # command that will be run as a daemon
my $commandPath  = "";   # fully qualified path to the command on this system
my $commandParms = "";   # command parameters for $command
my $commandName  = "";   # human-fiendly name of the program

# Init more vars
my $commandWPath = $commandPath . $command;
my $commandFull  = $commandWPath . " " . $commandParms;
my $pidFilename  = "/var/run/" . $command . ".pid";
my $userName     = getpwuid($>);    # returns 'root' if run as sudo

# check that Customization block has been set up
if ( $command eq "" && $commandPath eq "" && $commandName eq "" ) {
	errorExit('noSetup');
}

# check command path existence
if ( !-e $commandPath ) {
	errorExit('noPath');
}

# check for the daemon program
if ( !-e $commandPath . $command ) {
	errorExit('noProg');
}

# if not run as "root" then error out
if ( $userName ne "root" ) {
	errorExit('rootReq');
}

# IF > or < 1 argument, error
if ( @ARGV > 1 || @ARGV < 1 ) {
	errorExit('argReq');
}
my $argument = $ARGV[0];

# go do the voodoo that we do so well
if ( $argument eq 'start' ) {
	daemonStart();
} elsif ( $argument eq 'restart' ) {
	daemonRestart();
} elsif ( $argument eq 'stop' ) {
	daemonStop();
} elsif ( $argument eq 'pid' ) {
	daemonPid();
} elsif ( $argument eq 'help' || $argument eq '--help' || $argument eq '-help' || $argument eq '-h' ) {
	displayUsage();
} else {
	errorExit('unkArg');
}
exit(0);

# start daemon
sub daemonStart {
	# error out if the dameon is already running
	if ( -e $pidFilename ) {
		errorExit('alreadyRunning');
	}
	print "<<<Starting>>> the '$commandWPath' daemon.\n";
	my $result = system ( $commandFull );
	# TODO: add check to see if program is running and error out if it is not
	pidCreate();
	return;
}

# restart daemon
sub daemonRestart {
	my $result;
	# whoa, can't restart a program that is not running
	if ( !-e $pidFilename ) {
		errorExit('notRunning');
	}
	$result = system ( "pkill $command" );
	pidDelete();
	$result = system ( $commandFull );
	pidCreate();
	print "<<<Restarting>>> the '$commandWPath' daemon.\n";
	return;
}

# stop daemon
sub daemonStop {
	# can't stop a program that is not running
	if ( !-e $pidFilename ) {
		errorExit('notRunning');
	}
	my $result = system ( "pkill $command" );
	pidDelete();
	print "<<<Stopping>>> the '$commandWPath' daemon.\n";
	return;
}

# show pid
sub daemonPid {
	return;
}

# create pid file
sub pidCreate {
	#my $pid = qx( "pgrep $command" );
	#chomp $pid;
	my $pid = $command;

	open my $fhPid, ">>", $pidFilename or errorExit('errPid');
	if ( ! $fhPid ) {
		errorExit('errPid');
	}
	print $fhPid "$pid\n";
	close $fhPid;
	return;
}

# delete pid file
sub pidDelete {
	eval { unlink $pidFilename }; errorExit('errPidDelete') if $@;
	return;
}

# Display program usage help
sub displayUsage {
	print "\n$commandName manager\n";
	print "\n$0 is the process management utility for the '$commandWPath' daemon.\n\n";
	print "usage:\t\t$0 start|stop|restart|pid|help\n\n";
	print "where:\t\tstart\t\tStarts the $command daemon.\n";
	print "\t\trestart\t\tStops and starts the $command daemon.\n";
	print "\t\tstop\t\tStops the $command daemon.\n";
	print "\t\tpid\t\tDisplays the $command daemon's PID.\n";
	print "\t\thelp\t\tDisplays this help.\n";
	print "\nexample:\t$0 start\n\n";
	print "project:\thttp://code.google.com/p/daemon-kit/\n\n";
	return;
}

# Display an error and exit
sub errorExit {
	my ($errType) = @_;

	my $progArg = "";
	if ( defined $argument ) {
		$progArg = $argument;
	}

	my %errTypes = (
					 'noSetup' => {
								   'error'        => 'program has not been set up',
								   'explaination' => "The Customization block of '$0' has not been modified. Installation error.",
					 },
					 'noPath' => {
								   'error'        => 'command path doesn\'t exist',
								   'explaination' => "'$commandWPath' does not exist. Installation error.",
					 },
					 'noProg' => {
								   'error'        => 'daemon program doesn\'t exist',
								   'explaination' => "'$commandPath' does not exist. Installation error.",
					 },
					 'argReq' => {
								   'error'        => 'argument required',
								   'explaination' => "$0 requires a command line argument.",
					 },
					 'rootReq' => {
									'error'        => 'root privliges required',
									'explaination' => "$0 must be run as 'root'. You are '$userName'.",
					 },
					 'unkArg' => {
								   'error'        => 'unknown argument',
								   'explaination' => "Don't know what '$progArg' means.",
					 },
					 'alreadyRunning' => {
										   'error'        => 'daemon already running',
										   'explaination' => "Only one '$command' can run at a time.",
					 },
					 'notRunning' => {
									   'error'        => 'daemon not running',
									   'explaination' => "Can't stop or restart that which is not running.",
					 },
					 'errPid' => {
									   'error'        => "can't create PID file",
									   'explaination' => "Error creating the '$pidFilename' PID file.",
					 },
					 'errPidDelete' => {
									   'error'        => "can't delete PID file",
									   'explaination' => "Error deleting the '$pidFilename' PID file.",
					 },
	);

	print STDERR "ERROR:\t\t**" . $errTypes{$errType}{'error'} . "**\n";
	print STDERR "\t\t" . $errTypes{$errType}{'explaination'} . "\n";
	displayUsage();
	exit(1);
}
